#include "MainScene.h"
#include "OgreUtil.h"
#include "OISHandler.h"

MainScene::MainScene() {

	if (!OgreUtil::initializeOgre()) {
		OgreUtil::setExitAppTriggered();
		return;
	}
	window = OgreUtil::initializeWindow("2dTests");
	if (window == NULL) {
		OgreUtil::setExitAppTriggered();
		return;
	}
	oisHandler = OgreUtil::initializeWindowOIS(window);

	Ogre::Root* root = OgreUtil::getOgreRoot();
	//
	// Scene Manager
	//
	// Creamos un SceneManager generico
	mSceneMgr = root->createSceneManager(Ogre::ST_GENERIC, "mSceneMgr");
	//
	// Luz ambiente
	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.1, 0.1, 0.1));
	mSceneMgr->createLight()->setPosition(0, 100, 50);

	Ogre::Light* directionalLight = mSceneMgr->createLight("directionalLight");
	directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
	directionalLight->setDiffuseColour(Ogre::ColourValue(.25, .25, .25));
	directionalLight->setSpecularColour(Ogre::ColourValue(.25, .25, .25));
	directionalLight->setDirection(Ogre::Vector3(0, -1, 1));

	Ogre::ColourValue fadeColour(0.5, 0.5, 0.5);
	mSceneMgr->setFog(Ogre::FOG_EXP, fadeColour, 0.0005);
	//
	// Elegimos el tipo de sombra
	mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
	//
	//
	// Camera
	//
	// Creamos y configuramos la camara
	mCamera = mSceneMgr->createCamera("mCamera");
	mCamera->setPosition(Ogre::Vector3(0, 100, 150));
	mCamera->lookAt(Ogre::Vector3(0, 0, 0));
	mCamera->setNearClipDistance(5);
	mCamera->setFarClipDistance(1000);
	// Anadimos un Viewport y Adaptamos la proporcion de la camara para que encaje con el viewport
	viewport = window->addViewport(mCamera);
	mCamera->setAspectRatio(Ogre::Real(viewport->getActualWidth()) / Ogre::Real(viewport->getActualHeight()));
	//
	mCameraNodo = mSceneMgr->getRootSceneNode()->createChildSceneNode("mCameraNodo");
	mCameraNodo->attachObject(mCamera);

	//Guardo la camara para poderla usar luego en el calculo de las coordenadas del mouse
	oisHandler->setSceneValues(mSceneMgr, mCamera);

	//
	prepararRecursos();

	// Crea piso
	Ogre::Plane plane(Ogre::Vector3::UNIT_Y, -30);
	Ogre::MeshManager::getSingleton().createPlane("floor", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1000, 1000, 10, 10, true, 1, 8, 8, Ogre::Vector3::UNIT_Z);
	Ogre::Entity* floor = mSceneMgr->createEntity("Floor", "floor");
	floor->setMaterialName("Examples/BumpyMetal");
	mSceneMgr->getRootSceneNode()->attachObject(floor);

	// create an ogre head entity and place it at the origin
	Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "sphere.mesh");
	Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("HeadNode", Ogre::Vector3(0, 0, 0));
	headNode->attachObject(ogreHead);
	headNode->scale(.1, .1, .1);
	headNode->yaw(Ogre::Degree(-90));

	// create an ogre head entity and place it at 100,0,0
	Ogre::Entity* ogreHead2 = mSceneMgr->createEntity("Head2", "ogrehead.mesh");
	Ogre::SceneNode* headNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode("HeadNode2", Ogre::Vector3(100, 0, 0));
	headNode2->attachObject(ogreHead2);
	headNode2->scale(.5, .5, .5);
	headNode2->pitch(Ogre::Degree(-90));

	// create an ogre head entity and place it at 100,0,-100
	Ogre::Entity* ogreHead3 = mSceneMgr->createEntity("Head3", "ogrehead.mesh");
	Ogre::SceneNode* headNode3 = mSceneMgr->getRootSceneNode()->createChildSceneNode("HeadNode3", Ogre::Vector3(100, 0, -100));
	headNode3->attachObject(ogreHead3);
	headNode3->scale(.5, .5, .5);
	headNode3->roll(Ogre::Degree(-90));

	//
	// Timer
	//
	temporizador = new Ogre::Timer;
	ultimoFrame = 0.0f;
	deltaT = 0.0;
}

MainScene::~MainScene() {
	if (temporizador) {
		delete temporizador;
	}
	// Al destruir la root, cerramos Ogre de manera limpia
	Ogre::Root* root = OgreUtil::getOgreRoot();
	delete root;
}

void MainScene::prepararRecursos() {
	Ogre::ConfigFile ficheroConfig;

	ficheroConfig.load("resources.cfg");

	// Iterador para recorrer grupos
	Ogre::ConfigFile::SectionIterator iteradorGrupo = ficheroConfig.getSectionIterator();
	while (iteradorGrupo.hasMoreElements()) {
		//
		// Tomamos el nombre del grupo
		Ogre::String nombreGrupo = iteradorGrupo.peekNextKey();
		// Vamos a recorrer los archivos del grupo
		Ogre::ConfigFile::SettingsMultiMap *opciones = iteradorGrupo.getNext();
		//
		Ogre::ConfigFile::SettingsMultiMap::iterator it;
		for (it = opciones->begin(); it != opciones->end(); ++it) {
			Ogre::String nombreTipo = it->first;
			Ogre::String nombreArchivo = it->second;
			//
			cout << "Archivo: " << nombreArchivo << ", Tipo: " << nombreTipo << endl;
			//
			// Anadimos la localizacion del archivo con su nombre, su tipo y grupo
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(nombreArchivo, nombreTipo, nombreGrupo);
		}
	}
	//
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}

void MainScene::buclePrincipal() {
	if (OgreUtil::isExitAppTriggered()) {
		return;
	}

	// Lanzamos el timer
	temporizador->reset();
	// Mientras no se cierre la ventana
	while (!OgreUtil::isExitAppTriggered()) {
		// Actualizamos la entrada
		oisHandler->capture();

		// Sacamos todos los eventos de ventana de la pila
		Ogre::WindowEventUtilities::messagePump();

		// Renderizamos la escena
		Ogre::Root* root = OgreUtil::getOgreRoot();
		root->renderOneFrame();

		// Calculamos deltaT
		deltaT = temporizador->getMilliseconds() - ultimoFrame;
		ultimoFrame = temporizador->getMilliseconds();
	}
}
